/**
 * Copyright 2007 Bosco Curtu
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * 
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
 * Unless required by applicable law or agreed to in writing, 
 * software distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 * either express or implied. 
 * 
 * See the License for the specific language governing permissions and limitations 
 * under the License.
*/

package com.bcurtu.amigo.web;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;

import com.bcurtu.amigo.pojo.Amigo;
import com.bcurtu.amigo.pojo.Message;
import com.bcurtu.amigo.services.AmigoInvisibleBO;
import com.bcurtu.amigo.services.BlockingException;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.image.ImageCaptchaService;


public class AmigoWizardFormController extends AbstractWizardFormController {
	
	private Logger log =Logger.getLogger(this.getClass());

	private static final String DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME = "j_captcha_response";
	private static final String DEFAULT_CAPTCHA_PAGE_PARAMETER_NAME = "_finish";
	
	protected ImageCaptchaService captchaService;
	protected String captchaResponseParameterName = DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME;
	private String captchaPageParameter = DEFAULT_CAPTCHA_PAGE_PARAMETER_NAME;
	
	private String successView;
	private String errorView;
	private AmigoInvisibleBO bo;
	
	private ResourceBundleMessageSource bundle;
	private LocaleResolver localeResolver;
	
	
	public LocaleResolver getLocaleResolver() {
		return localeResolver;
	}
	public void setLocaleResolver(LocaleResolver localeResolver) {
		this.localeResolver = localeResolver;
	}
	public ResourceBundleMessageSource getBundle() {
		return bundle;
	}
	public void setBundle(ResourceBundleMessageSource bundle) {
		this.bundle = bundle;
	}
	public String getErrorView() {
		return errorView;
	}
	public void setErrorView(String errorView) {
		this.errorView = errorView;
	}
	public void setSuccessView(String successView) {
		this.successView = successView;
	}
	public AmigoInvisibleBO getBo() {
		return bo;
	}
	public void setBo(AmigoInvisibleBO bo) {
		this.bo = bo;
	}
	public void setCaptchaService(ImageCaptchaService captchaService) {
		this.captchaService = captchaService;
	}
	public void setCaptchaResponseParameterName(String captchaResponseParameterName) {
		this.captchaResponseParameterName = captchaResponseParameterName;
	}
	public void setCaptchaPageParameter(String captchaPageParameter) {
		this.captchaPageParameter = captchaPageParameter;
	}
		
	/**
	 * Delegates request to CAPTCHA validation, subclasses which overrides this 
	 * method must manually call <code>{@link #validateCaptcha(HttpServletRequest, BindException)}</code>
	 * or explicitly call super method.
	 * 
	 * @see #validateCaptcha(HttpServletRequest, BindException)
	 * @see org.springframework.web.servlet.mvc.BaseCommandController#onBindAndValidate(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException)
	 */
	@Override
	protected void onBind(HttpServletRequest request, Object command, BindException errors) throws Exception {
		if (request.getParameter(captchaPageParameter)!=null){
			log.debug("onBind... Validate Captcha!");
			validateCaptcha(request, errors, command);
		}
	}	
	
	/**
	 * Validate CAPTCHA response, if response isn`t valid creates new error object 
	 * and put him to errors holder.
	 * 
	 * @param request current servlet request
	 * @param errors errors holder
	 */
	protected void validateCaptcha(HttpServletRequest request, BindException errors, Object command){
		boolean isResponseCorrect = false;
		
        //remenber that we need an id to validate!
        String captchaId = request.getSession().getId();
        //retrieve the response
        String response = request.getParameter(captchaResponseParameterName);
        //validate response
        try {			
			if(response != null){
				isResponseCorrect =
					captchaService.validateResponseForID(captchaId, response);
			}
		} catch (CaptchaServiceException e) {
		    //should not happen, may be thrown if the id is not valid			
		}
		
		if(!isResponseCorrect){
			//prepare object error, captcha response isn`t valid
	        String objectName = "Captcha";
			String[] codes = {"captcha.error"};
			Object[] arguments = {};
			String defaultMessage = "captcha.error";
			ObjectError oe = new ObjectError(objectName, codes, arguments, defaultMessage);
			errors.addError(oe);
			
			createConfirmationList(request,(AmigoCommand)command);

		}         
	}

	protected ModelAndView processFinish(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, BindException arg3) throws Exception {
		log.debug("onSubmit.");
		
		AmigoCommand cmd=(AmigoCommand)arg2;
		
		String[] names=cmd.getName();
		String[] emails=cmd.getEmail();
		Integer[] ids=cmd.getId();
		String[] excludes=cmd.getExclude();
		
		
		if (names.length<3){
			return new ModelAndView(getErrorView(),"exception",bundle.getMessage("form.val.amigo.min",new String[0],localeResolver.resolveLocale(arg0)));			
		}
		if (names.length>75){
			return new ModelAndView(getErrorView(),"exception",bundle.getMessage("form.val.amigo.max",new String[0],localeResolver.resolveLocale(arg0)));			
		}
		if (cmd.getBody().indexOf("$AMIGO")<0){
			return new ModelAndView(getErrorView(),"exception",bundle.getMessage("form.val.body",new String[0],localeResolver.resolveLocale(arg0)));			
		}			
			
		Message mes=new Message(cmd.getSubject(),cmd.getBody());
		
		List<Amigo> amigos=new ArrayList<Amigo>();
		
		for (int i=0;i<names.length;i++){
			if (names[i]!=null && names[i].length()>0){
				Amigo amigo=new Amigo();
				amigo.setId(ids[i]);
				amigo.setName(names[i]);
				amigo.setEmail(emails[i]);
				if (excludes[i].length()>0){
					amigo.setExclude(Integer.parseInt(excludes[i]));
				} else {
					amigo.setExclude(-1);
				}
				amigos.add(amigo);
				log.info("Added a new Amigo:"+amigo);
			}
		}
		
		log.info("Sorteando amigos");
		
		try{
			String id=bo.sortea(amigos, mes);			
			return new ModelAndView(successView,"ticket",id);
		} catch (BlockingException ex){			
			return new ModelAndView(getErrorView(),"exception",bundle.getMessage("error.bloqueo",new String[0],localeResolver.resolveLocale(arg0)));			
		} catch (Exception ex){			
			return new ModelAndView(getErrorView(),"exception",ex.getMessage());			
		}
	}


	@Override
	protected Object formBackingObject(HttpServletRequest arg0) throws Exception {
		log.debug("formBackingObject");
		AmigoCommand cmd=new AmigoCommand();
		return cmd;
	}
	@Override
	protected void postProcessPage(HttpServletRequest req, Object obj, Errors arg2, int page) throws Exception {
		log.debug("postProcessPage="+page);
		AmigoCommand cmd=(AmigoCommand)obj;
		if (page==1){
			createConfirmationList(req,cmd);
		}
	}

	private void createConfirmationList(HttpServletRequest req, AmigoCommand cmd){
		int i=0;
		while(i<cmd.getId().length){
			if (cmd.getName()[i]!=null && cmd.getName()[i].length()>0){
				req.setAttribute("name"+i,cmd.getName()[i]);
				req.setAttribute("email"+i,cmd.getEmail()[i]);
				req.setAttribute("exclude"+i,cmd.getExclude()[i]);
			} else {
				break;
			}
			i++;
		}
		req.setAttribute("ids",i);
		log.debug("createConfirmationList:ids="+i);
	}
	
	
}
